package vn.edu.uit.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.URLEncoder;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerPNames;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import android.util.Log;

/**
 * The Class UITHttpRequest.
 */
public class UITHttpRequest 
{
	
	/**
	 * The Enum RequestMethod.
	 */
	public enum RequestMethod
	 {
		 
 		/** The get. */
 		GET,
		 
 		/** The post. */
 		POST
	 }
	
	/** The params. */
	private ArrayList <NameValuePair> params;
    
    /** The headers. */
    private ArrayList <NameValuePair> headers;
    
    /** The url. */
    private String url;
    
    /** The response code. */
    private int responseCode;
    
    /** The message. */
    private String message;
    
    /** The timeout. */
    private int timeout=60000;
    
    //-----------method------------------
    /**
     * Gets the error message.
     *
     * @return the error message
     */
    public String getErrorMessage() {
        return message;
    }
    

    /**
     * Instantiates a new UIT http request.
     *
     * @param context the context
     * @param url the url
     */
    public UITHttpRequest(String url)
    {
        this.url = url;
        params = new ArrayList<NameValuePair>();
        headers = new ArrayList<NameValuePair>();
    }
    
    /**
     * Adds the param.
     *
     * @param name the name
     * @param value the value
     */
    public void addParam(String name, String value)
    {
        params.add(new BasicNameValuePair(name, value));
    }
    
    /**
     * Adds the header.
     *
     * @param name the name
     * @param value the value
     */
    public void addHeader(String name, String value)
    {
        headers.add(new BasicNameValuePair(name, value));
    }
    
   
    /**
     * Do execute.
     *
     * @param method the method
     * @return the jSON object
     * @throws Exception the exception
     */
    public JSONObject doExecute(RequestMethod method) throws Exception
    {
        switch(method) {
            case GET:
            {
                //add parameters
                String combinedParams = "";
                if(!params.isEmpty())
                {
                    combinedParams += "?";
                    for(NameValuePair p : params)
                    {
                        String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue(),"UTF-8");
                        if(combinedParams.length() > 1)
                        {
                            combinedParams  +=  "&" + paramString;
                        }
                        else
                        {
                            combinedParams += paramString;
                        }
                    }
                }
                HttpGet request = new HttpGet(url + combinedParams);
                //add headers
                for(NameValuePair h : headers)
                {
                    request.addHeader(h.getName(), h.getValue());
                }
                return executeRequest(request, url);
            }
            case POST:
            {
                HttpPost request = new HttpPost(url);
                //add headers
                for(NameValuePair h : headers)
                {
                    request.addHeader(h.getName(), h.getValue());
                }
                if(!params.isEmpty())
                {
                    request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
                }
                return executeRequest(request, url);
            }
        }
		return null;
    }

    

    /**
     * Execute request.
     *
     * @param request the request
     * @param url the url
     * @return the jSON object
     */
    private JSONObject executeRequest(HttpUriRequest request, String url)
    {
    	JSONObject jsonResult = null;
    	 
    	SchemeRegistry schemeRegistry = new SchemeRegistry();
    	schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    	schemeRegistry.register(new Scheme("https", new UITEasySSLSocketFactory(), 443));
    	 
    	HttpParams params = new BasicHttpParams();
    	params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
    	params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
    	params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
    	HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
    	//set time out
    	HttpConnectionParams.setConnectionTimeout(params, timeout);
		HttpConnectionParams.setSoTimeout(params, timeout);
		
    	ClientConnectionManager cm = new SingleClientConnManager(params, schemeRegistry);
    	
        DefaultHttpClient client = new DefaultHttpClient(cm, params); 

        HttpResponse httpResponse;
        
        String response = "";
        try 
        {
            httpResponse = client.execute(request);
            responseCode = httpResponse.getStatusLine().getStatusCode();
            message = httpResponse.getStatusLine().getReasonPhrase();
            if(responseCode !=200 )
            {
            	client.getConnectionManager().shutdown();
            }
            HttpEntity entity = httpResponse.getEntity();
            if (entity != null) 
            {
                InputStream instream = entity.getContent();
                response = convertStreamToString(instream);
                
                //Only response
                try{
	                DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
	                DocumentBuilder builder = domFactory.newDocumentBuilder();
	                Document doc =  builder.parse(new InputSource(new StringReader(response)));
	                NodeList nl = doc.getElementsByTagName("response");    
	                Element firstNameElement = (Element)nl.item(0);
	                response = firstNameElement.getChildNodes().item(0).getNodeValue();
	                Log.d("JSON", response);
                }catch(Exception e){
                }
                
                // Closing the input stream will trigger connection release
                instream.close();
            }
        }
        catch (ClientProtocolException e)  
        {
            client.getConnectionManager().shutdown();
            e.printStackTrace();
        } 
        catch (IOException e) 
        {
            client.getConnectionManager().shutdown();
            e.printStackTrace();
        }
        finally {
        	client.getConnectionManager().shutdown();
        }
       
		try {
			jsonResult = new JSONObject(response);
		} catch (JSONException e) {
			jsonResult = new JSONObject();
		}
        return jsonResult;
    }
    
    /**
     * Convert stream to string.
     *
     * @param is the is
     * @return the string
     */
    private static String convertStreamToString(InputStream is) 
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try
        {
        	
            while ((line = reader.readLine()) != null) 
            {
                sb.append(line + "\n");
            }
        } catch (IOException e) 
        {
            e.printStackTrace();
        } 
        finally 
        {
            try 
            {
                is.close();
            } catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }

}


